package top.blackr.folivora.common.security.crud.repository;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import top.blackr.folivora.common.core.constants.CommonConstants;
import top.blackr.folivora.common.core.enums.ResultEnum;
import top.blackr.folivora.common.core.exception.BizException;
import top.blackr.folivora.common.security.auth.SecUser;
import top.blackr.folivora.common.security.auth.SecurityUtils;
import top.blackr.folivora.common.security.crud.mapper.SysMenuMapper;
import top.blackr.folivora.common.security.crud.mapper.SysRoleMenuMapper;
import top.blackr.folivora.common.security.crud.model.entity.SysMenu;
import top.blackr.folivora.common.security.crud.model.entity.SysRole;
import top.blackr.folivora.common.security.crud.model.entity.SysRoleMenu;
import top.blackr.folivora.common.security.crud.model.vo.SysMenuVo;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@AllArgsConstructor
public class SysMenuRepository extends CrudRepository<SysMenuMapper, SysMenu> {

    private final SysRoleRepository roleRepository;
    private final SysRoleMenuMapper sysRoleMenuMapper;

    public List<Tree<Integer>> treeMenu(boolean lazy, Integer parentId) {
        if (lazy) {
            Integer parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
            List<TreeNode<Integer>> collect = baseMapper
                    .selectList(Wrappers.<SysMenu>lambdaQuery()
                            .eq(SysMenu::getParentId, parent).orderByAsc(SysMenu::getSort))
                    .stream().map(getNodeFunction()).collect(Collectors.toList());
            return TreeUtil.build(collect, parent);
        }
        List<TreeNode<Integer>> collect = baseMapper
                .selectList(Wrappers.<SysMenu>lambdaQuery().orderByAsc(SysMenu::getSort)).stream()
                .map(getNodeFunction()).collect(Collectors.toList());
        return TreeUtil.build(collect, CommonConstants.MENU_TREE_ROOT_ID);
    }

    public Boolean saveMenu(SysMenuVo sysMenuVo) {
        SysMenu sysMenu = BeanUtil.copy(sysMenuVo, SysMenu.class);
        return this.save(sysMenu);
    }

    public Boolean updateMenu(SysMenuVo sysMenuVo) {
        SysMenu sysMenu = BeanUtil.copy(sysMenuVo, SysMenu.class);
        return this.updateById(sysMenu);
    }

    public Boolean delMenu(SysMenuVo sysMenuVo) {
        // 查询父节点为当前节点的节点
        List<SysMenu> menuList = this.list(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getParentId, sysMenuVo.getMenuId()));
        if (CollUtil.isNotEmpty(menuList)) {
            // 菜单含有下级不能删除
            throw new BizException(ResultEnum.FAIL);
        }
        // 删除角色关联的菜单
        sysRoleMenuMapper.delete(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getMenuId, sysMenuVo.getMenuId()));
        // 删除当前菜单及其子菜单
        return this.removeById(sysMenuVo.getMenuId());
    }

    public Object menuAuthority() {
        SecUser user = SecurityUtils.getUser();
        List<String> roleCodes = user.getRoles();
        if (ObjectUtil.isEmpty(roleCodes)) {
            return Collections.emptyList();
        }
        List<SysRole> roles = roleRepository.list(Wrappers.<SysRole>lambdaQuery()
                .in(SysRole::getRoleCode, roleCodes));
        Set<Integer> roleIds = roles.stream().map(SysRole::getRoleId).collect(Collectors.toSet());
        // 获取角色关联的菜单id
        Set<Integer> menuIds = sysRoleMenuMapper.selectList(Wrappers.<SysRoleMenu>lambdaQuery()
                        .in(SysRoleMenu::getRoleId, roleIds))
                .stream().map(SysRoleMenu::getMenuId)
                .collect(Collectors.toSet());
        if (ObjectUtil.isEmpty(menuIds)) {
            return Collections.emptyList();
        }
        // 获取指定菜单信息
        List<TreeNode<Integer>> collect = baseMapper
                .selectList(Wrappers.<SysMenu>lambdaQuery()
                        .in(SysMenu::getMenuId, menuIds).orderByAsc(SysMenu::getSort))
                .stream()
                .map(getNodeFunction()).collect(Collectors.toList());
        // 构建树
        return TreeUtil.build(collect, CommonConstants.MENU_TREE_ROOT_ID);
    }

    @NotNull
    private Function<SysMenu, TreeNode<Integer>> getNodeFunction() {
        return menu -> {
            TreeNode<Integer> node = new TreeNode<>();
            node.setId(menu.getMenuId());
            node.setName(menu.getName());
            node.setParentId(menu.getParentId());
            node.setWeight(menu.getSort());
            // 扩展属性
            Map<String, Object> extra = new HashMap<>(9);
            extra.put("icon", menu.getIcon());
            extra.put("path", menu.getPath());
            extra.put("type", menu.getType());
            extra.put("permission", menu.getPermission());
            extra.put("sort", menu.getSort());
            node.setExtra(extra);
            return node;
        };
    }

    public List<SysMenuVo> getMenusByRoleIds(@Param("roleIds") List<Integer> roleIds) {
        return baseMapper.getMenusByRoleIds(roleIds);
    }
}
